#include <algorithm>
#include <iostream>

#include "DLM_Coordinator.h"
#include "dlm.h"

using namespace std;

//======================================================================

DLM_Coordinator::DLM_Coordinator()
{
}

//======================================================================

void DLM_Coordinator::run(std::ostream &cout)
{
	string command, line;
	int words = 0;
	
	do
	{
		cout << endl << "~> ";
	
		line.clear();
		
		getline(cin, line);				
		transform(line.begin(), line.end(), line.begin(), ::tolower);		
		stringstream ss(line);
		
		words = word_count(line);
		if(words == 0)
		{
			continue;
		}
		
		ss >> command;
		
		if(command == "quit" && words == 1)
		{
			do_quit();
			break;
		
		} else if(command == "pids" && words == 1)
		{	
			do_pids();
		
		} else if(command == "help" && words == 1)
		{
			do_help();
		
		} else if(command == "lock")
		{
			do_lock(ss, words);
			
		} else if(command == "unlock")
		{
			do_unlock(ss, words);
			
		} else if(command == "trylock")
		{
			do_trylock(ss, words);
			
		} else
		{
			wrong_command();
			continue;
		}	
				
	} while(true);
}

//======================================================================

void DLM_Coordinator::do_quit() const
{	
	vector<pid_t> pid_vector = get_client_pid_vector();
	cout << "Quiting clients" << endl;
	for(int i = 0; i < int(pid_vector.size()); ++i)
	{
		send_msg(MSG_FLAG_QUIT, pid_vector[i], 0, 0, 0);
	}
}

//======================================================================

void DLM_Coordinator::do_pids() const
{	
	vector<pid_t> pid_vector = get_client_pid_vector();
	cout << "writing pid list: size == " << pid_vector.size() << endl;
	for(int i = 0; i < int(pid_vector.size()); ++i)
	{
		cout << "Client pid: " << pid_vector[i] << endl;
	}
}

//======================================================================

void DLM_Coordinator::do_help() const
{
	cout << "Available commands:" << endl;
	cout << "lock <pid> <resource_id> <ex | pr | pw |  cw | cr> [timeout]" << endl;
	cout << "unlock <pid> <resource_id>" << endl;
	cout << "trylock <pid> <resource_id> <ex | pr | pw |  cw | cr>" << endl;
	cout << "pids - to show client pid numbers" << endl;
	cout << "quit - to exit application" << endl;
	cout << "help" << endl;
}

//======================================================================

void DLM_Coordinator::do_lock(stringstream& ss, int argc) const
{
	if(argc < 4 || argc > 5)
	{
		cout << "Wrong argument number!" << endl;
		return;
	}
	
	pid_t pid;
	int resource_id;
	string lock_name;
	long timeout = 0;
	
	if(!(ss >> pid))
	{
		cout << "Wrong pid value!" << endl;
		return;
	}
	
	if(!(ss >> resource_id))
	{
		cout << "Wrong resource ID value!" << endl;
		return;
	}
	
	ss >> lock_name;
	
	int lock_type = get_lock_num(lock_name);
	
	if(lock_type == WRONG_LOCK_NAME)
	{
		cout << "Unrecognized lock type name!" << endl;
		return;
	}
	
	if(argc == 5)
	{
		if(!(ss >> timeout))
		{
			cout << "Wrong timeout value!" << endl;
			return;
		}
	}
	
	bool result = send_msg(MSG_FLAG_LOCK, pid, resource_id, lock_type, timeout) == DLM_RETURN_OK;

	if(!result)
	{
		cout << "Error! Can't sent message to specified client (pid: " << pid << ")" << endl;
	}
}

//======================================================================

void DLM_Coordinator::do_unlock(stringstream& ss, int argc) const
{
	if(argc != 3)
	{
		cout << "Wrong argument number!" << endl;
		return;
	}
	
	pid_t pid;
	int resource_id;
	
	if(!(ss >> pid))
	{
		cout << "Wrong pid value!" << endl;
		return;
	}
	
	if(!(ss >> resource_id))
	{
		cout << "Wrong resource ID value!" << endl;
		return;
	}
	
	bool result = send_msg(MSG_FLAG_UNLOCK, pid, resource_id, 0, 0) == DLM_RETURN_OK;
	
	if(!result)
	{
		cout << "Error! Can't sent message to specified client (pid: " << pid << ")" << endl;
	}
}

//======================================================================

void DLM_Coordinator::do_trylock(stringstream& ss, int argc) const
{
	if(argc != 4)
	{
		cout << "Wrong argument number!" << endl;
		return;
	}
	
	pid_t pid;
	int resource_id;
	string lock_name;
	
	if(!(ss >> pid))
	{
		cout << "Wrong pid value!" << endl;
		return;
	}
	
	if(!(ss >> resource_id))
	{
		cout << "Wrong resource ID value!" << endl;
		return;
	}
	
	ss >> lock_name;
	
	int lock_type = get_lock_num(lock_name);
	
	if(lock_type == WRONG_LOCK_NAME)
	{
		cout << "Unrecognized lock type name!" << endl;
		return;
	}
	
	bool result = send_msg(MSG_FLAG_TRYLOCK, pid, resource_id, lock_type, 0) == DLM_RETURN_OK;
	
	if(!result)
	{
		cout << "Error! Can't sent message to specified client (pid: " << pid << ")" << endl;
	}
}

//======================================================================

void DLM_Coordinator::wrong_command() const
{
	cout << "Wrong command! Type 'help' to see available commands." << endl;
}

//======================================================================

int DLM_Coordinator::word_count(const string& line) const
{
	stringstream ss(line);
	string word;
	int num = 0;
	
	while(ss >> word)
	{
		++num;
	}
	
	return num;
}

//======================================================================

int DLM_Coordinator::get_lock_num(const string& name) const
{
	if(name == "cr") return CR;
	if(name == "cw") return CW;
	if(name == "pr") return PR;
	if(name == "pw") return PW;
	if(name == "ex") return EX;
		
	return WRONG_LOCK_NAME;
}

//======================================================================

